package controller.parameterpanels;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;

import model.auxillary.Parameter;
import view.NumericalTextField;

/**
 * The {@code ListenerNumericalTF} class controls the user written
 * content of a parameter's text field where only numerical values should be
 * entered. If the input is valid the associated parameter gets set with it's
 * value. It also controls the behavior of the text field. 
 * @author Oliver Eckstein & Sebastian Perlwitz
 *
 */
public class ListenerNumericalTF implements DocumentListener {
	
	/**
	 * The parameter's text field.
	 */
	private NumericalTextField valueTF;
	
	/**
	 * The listener's parameter which gets controlled.
	 */
	private Parameter param;
	
	/**
	 * The controller of the panel of a process input text field.
	 */
	private CtrInputParameterPanel controllerInputParamPanel;
	
	/**
	 * The controller of the panel of a facility text field.
	 */
	private CtrFacilityPanel controllerFacilityPanel; //#Neu
	
	/**
	 * The controller of the panel of a factory text field.
	 */
	private CtrFactoryPanel controllerFactoryPanel; //#Neu
	
	/**
	 * To create a new {@code ListenerNumericalTF}.
	 * @param valueTF the text field that gets controlled.
	 * @param param the parameter to be referenced.
	 * @param controller the controller of the view where the text field is
	 * located.
	 */
	public ListenerNumericalTF(
			NumericalTextField valueTF,
			Parameter param,
			CtrInputParameterPanel controller) {
		this.valueTF = valueTF;
		this.param = param;		
		this.controllerInputParamPanel = controller;
	}
	
	//#Neu
	/**
	 * To create a new {@code ListenerNumericalTF}.
	 * @param valueTF the text field that gets controlled.
	 * @param param the parameter to be referenced.
	 * @param controller the controller of the view where the text field is
	 * located.
	 */
	public ListenerNumericalTF(
			NumericalTextField valueTF,
			Parameter param,
			CtrFacilityPanel controller) {
		this.valueTF = valueTF;
		this.param = param;		
		this.controllerFacilityPanel = controller;
	}
	
	//#Neu
	/**
	 * To create a new {@code ListenerNumericalTF}.
	 * @param valueTF the text field that gets controlled.
	 * @param param the parameter to be referenced.
	 * @param controller the controller of the view where the text field is
	 * located.
	 */
	public ListenerNumericalTF(
			NumericalTextField valueTF,
			Parameter param,
			CtrFactoryPanel controller) {
		this.valueTF = valueTF;
		this.param = param;		
		this.controllerFactoryPanel = controller;
	}
	
	@Override
	public void changedUpdate(DocumentEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void insertUpdate(DocumentEvent e) {
		updateValue(e);
	}

	@Override
	public void removeUpdate(DocumentEvent e) {
		updateValue(e);
	}
	
	/**
     * To handle user input.
     * @param e the document event.
     */
	private void updateValue(DocumentEvent e) {
		String txt = "";
		try {
            txt = e.getDocument().getText(0, e.getDocument().getLength());
        } catch (BadLocationException e1) {            
            e1.printStackTrace();
        }
		
		//#Neu
		if( controllerInputParamPanel !=null) {
			// Former input was removed.
			if(txt.equals("")) {
				if(valueTF.getErrorStatus()) {
					valueTF.clearError();
					controllerInputParamPanel.removeInvalidInput();				
				} else {
					controllerInputParamPanel.removeValidInput();
				}
				param.setValue(Double.NaN);
				return;
			}
		} else if(controllerFacilityPanel != null) {
			// Former input was removed.
			if(txt.equals("")) {
				if(valueTF.getErrorStatus()) {
					valueTF.clearError();
					controllerFacilityPanel.removeInvalidInput();				
				}
				param.setValue(Double.NaN);
				return;
			}
		} else if(controllerFactoryPanel != null) {
			// Former input was removed.
			if(txt.equals("")) {
				if(valueTF.getErrorStatus()) {
					valueTF.clearError();
					controllerFactoryPanel.removeInvalidInput();				
				}
				param.setValue(Double.NaN);
				return;
			}
		} 
		
		Double newValue;		      
        try {            
            /*
             * The input 5d or 5f is actually valid:
             * 5d = (Double) 5.0; 5f = (Float) 5.0.
             * To prevent this another letter gets appended to make
             * Double.valueOf(String) throw a NumberFormatException.
             */
            
            if (txt.contains("d") || txt.contains("f")) {
                txt += "a";
            }
            
            //#Neu
            if(controllerInputParamPanel != null) {
            	// To prevent causing an error when negative numbers get written.
                if (txt.equals("-") || txt.equals("+")) {                                
                	if(valueTF.getErrorStatus()) {
        				valueTF.clearError();
        				controllerInputParamPanel.removeInvalidInput();
        			}
                	return;
                }
                // Try to cast the input to a double value.
                newValue = Double.valueOf(txt);            
                param.setValue(newValue);
                controllerInputParamPanel.addValidInput();
                
                // A formerly error was corrected.
                if(valueTF.getErrorStatus()) {
    				valueTF.clearError();
    				controllerInputParamPanel.removeInvalidInput();				
    			}            
            } else if(controllerFacilityPanel != null) {
            	// To prevent causing an error when negative numbers get written.
                if (txt.equals("-") || txt.equals("+")) {                                
                	if(valueTF.getErrorStatus()) {
        				valueTF.clearError();
        				controllerFacilityPanel.removeInvalidInput();
        			}
                	return;
                }
                // Try to cast the input to a double value.
                newValue = Double.valueOf(txt);            
                param.setValue(newValue);
                
                // A formerly error was corrected.
                if(valueTF.getErrorStatus()) {
    				valueTF.clearError();
    				controllerFacilityPanel.removeInvalidInput();				
    			}       
            } else if(controllerFactoryPanel != null) {
            	// To prevent causing an error when negative numbers get written.
                if (txt.equals("-") || txt.equals("+")) {                                
                	if(valueTF.getErrorStatus()) {
        				valueTF.clearError();
        				controllerFactoryPanel.removeInvalidInput();
        			}
                	return;
                }
                // Try to cast the input to a double value.
                newValue = Double.valueOf(txt);            
                param.setValue(newValue);
                
                // A formerly error was corrected.
                if(valueTF.getErrorStatus()) {
    				valueTF.clearError();
    				controllerFactoryPanel.removeInvalidInput();				
    			}   
            }
            
        } catch (NumberFormatException nfe) {
        	
        	//#Neu
        	if(controllerInputParamPanel != null) {
        		// The input isn't valid.
                newValue = Double.NaN;
                valueTF.showError();
                controllerInputParamPanel.addInvalidInput();
        	} else if(controllerFacilityPanel != null) {
        		// The input isn't valid.
                newValue = Double.NaN;
                valueTF.showError();
                controllerFacilityPanel.addInvalidInput();
        	} else if(controllerFactoryPanel != null) {
        		// The input isn't valid.
                newValue = Double.NaN;
                valueTF.showError();
                controllerFactoryPanel.addInvalidInput();
        	}
        }
	}

}
